package org.convallaria.system.biz.service.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.convallaria.system.biz.config.PerformanceConfig;
import org.convallaria.system.biz.service.PerformanceMonitorService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.OperatingSystemMXBean;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;

/**
 * 性能监控服务实现
 * 
 * @author convallaria
 * @since 1.0.0
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PerformanceMonitorServiceImpl implements PerformanceMonitorService {

    private final RedisTemplate<String, String> redisTemplate;
    private final PerformanceConfig performanceConfig;

    private static final String PERFORMANCE_PREFIX = "performance:";
    private static final String API_PERFORMANCE_KEY = PERFORMANCE_PREFIX + "api:";
    private static final String DB_PERFORMANCE_KEY = PERFORMANCE_PREFIX + "db:";
    private static final String CACHE_PERFORMANCE_KEY = PERFORMANCE_PREFIX + "cache:";
    private static final String SLOW_OPERATIONS_KEY = PERFORMANCE_PREFIX + "slow:";
    private static final String STATISTICS_KEY = PERFORMANCE_PREFIX + "stats:";

    @Override
    public void recordApiPerformance(String method, long duration, boolean success) {
        if (!performanceConfig.isEnabled() || !shouldSample()) {
            return;
        }

        try {
            String key = API_PERFORMANCE_KEY + method;
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            
            // 记录性能数据
            redisTemplate.opsForHash().put(key, timestamp, 
                String.format("%d,%s", duration, success));
            
            // 设置过期时间
            redisTemplate.expire(key, Duration.ofDays(performanceConfig.getRetentionDays()));

            // 记录慢操作
            if (duration > performanceConfig.getSlowApiThreshold()) {
                recordSlowOperation(method, "API", duration, String.format("Method: %s", method));
            }

        } catch (Exception e) {
            log.error("记录API性能数据失败", e);
        }
    }

    @Override
    public void recordDatabasePerformance(String sql, long duration, boolean success) {
        if (!performanceConfig.isEnabled() || !shouldSample()) {
            return;
        }

        try {
            String key = DB_PERFORMANCE_KEY + hashSql(sql);
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            
            // 记录性能数据
            redisTemplate.opsForHash().put(key, timestamp, 
                String.format("%d,%s", duration, success));
            
            // 设置过期时间
            redisTemplate.expire(key, Duration.ofDays(performanceConfig.getRetentionDays()));

            // 记录慢查询
            if (duration > performanceConfig.getSlowQueryThreshold()) {
                recordSlowOperation(sql, "DB", duration, String.format("SQL: %s", sql));
            }

        } catch (Exception e) {
            log.error("记录数据库性能数据失败", e);
        }
    }

    @Override
    public void recordCachePerformance(String operation, String key, long duration, boolean hit) {
        if (!performanceConfig.isEnabled() || !shouldSample()) {
            return;
        }

        try {
            String cacheKey = CACHE_PERFORMANCE_KEY + operation;
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
            
            // 记录性能数据
            redisTemplate.opsForHash().put(cacheKey, timestamp, 
                String.format("%d,%s", duration, hit));
            
            // 设置过期时间
            redisTemplate.expire(cacheKey, Duration.ofDays(performanceConfig.getRetentionDays()));

        } catch (Exception e) {
            log.error("记录缓存性能数据失败", e);
        }
    }

    @Override
    public PerformanceStatistics getPerformanceStatistics(int timeRange) {
        try {
            // TODO: 性能统计计算逻辑
            // 从Redis中读取性能数据并计算统计信息
            
            return new PerformanceStatistics(
                1000L, 950L, 50L, 120.5, 300.0, 500.0, 10L, LocalDateTime.now()
            );
        } catch (Exception e) {
            log.error("获取性能统计失败", e);
            return new PerformanceStatistics(0L, 0L, 0L, 0.0, 0.0, 0.0, 0L, LocalDateTime.now());
        }
    }

    @Override
    public List<SlowOperation> getSlowOperations(int limit) {
        try {
            // TODO: 慢操作查询逻辑
            // 从Redis中读取慢操作数据
            
            List<SlowOperation> operations = new ArrayList<>();
            operations.add(new SlowOperation(
                "login", "API", 1200L, LocalDateTime.now().minusMinutes(5), "User login operation"
            ));
            operations.add(new SlowOperation(
                "SELECT * FROM sys_user", "DB", 800L, LocalDateTime.now().minusMinutes(10), "User query"
            ));
            
            return operations.stream().limit(limit).toList();
        } catch (Exception e) {
            log.error("获取慢操作列表失败", e);
            return new ArrayList<>();
        }
    }

    @Override
    public SystemResourceUsage getSystemResourceUsage() {
        try {
            OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
            MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
            
            // CPU使用率
            double cpuUsage = 0.0;
            try {
                // 尝试获取CPU使用率，如果不可用则返回0
                if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
                    com.sun.management.OperatingSystemMXBean sunOsBean = (com.sun.management.OperatingSystemMXBean) osBean;
                    cpuUsage = sunOsBean.getProcessCpuLoad() * 100;
                }
            } catch (Exception e) {
                log.debug("无法获取CPU使用率", e);
            }
            
            // 内存使用情况
            long memoryUsed = memoryBean.getHeapMemoryUsage().getUsed();
            long memoryTotal = memoryBean.getHeapMemoryUsage().getMax();
            
            // 磁盘使用情况（简化实现）
            long diskUsed = 0L;
            long diskTotal = 0L;
            
            // 连接池使用情况（简化实现）
            int activeConnections = 0;
            int maxConnections = 100;
            
            return new SystemResourceUsage(
                cpuUsage, memoryUsed, memoryTotal, diskUsed, diskTotal,
                activeConnections, maxConnections, LocalDateTime.now()
            );
        } catch (Exception e) {
            log.error("获取系统资源使用情况失败", e);
            return new SystemResourceUsage(0.0, 0L, 0L, 0L, 0L, 0, 0, LocalDateTime.now());
        }
    }

    @Override
    @Scheduled(fixedRate = 3600000) // 每小时执行一次
    public void cleanExpiredData() {
        try {
            // 清理过期的性能数据
            String pattern = PERFORMANCE_PREFIX + "*";
            var keys = redisTemplate.keys(pattern);
            
            if (keys != null) {
                int cleanedCount = 0;
                for (String key : keys) {
                    if (redisTemplate.getExpire(key) == -1) {
                        redisTemplate.expire(key, Duration.ofDays(performanceConfig.getRetentionDays()));
                        cleanedCount++;
                    }
                }
                
                if (cleanedCount > 0) {
                    log.info("清理性能数据: {} 个键", cleanedCount);
                }
            }
        } catch (Exception e) {
            log.error("清理过期性能数据失败", e);
        }
    }

    /**
     * 判断是否应该采样
     */
    private boolean shouldSample() {
        return ThreadLocalRandom.current().nextDouble() < performanceConfig.getSamplingRate();
    }

    /**
     * 记录慢操作
     */
    private void recordSlowOperation(String operation, String type, long duration, String details) {
        try {
            String key = SLOW_OPERATIONS_KEY + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            String value = String.format("%s|%s|%d|%s|%s", 
                operation, type, duration, 
                LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME), details);
            
            redisTemplate.opsForList().leftPush(key, value);
            redisTemplate.expire(key, Duration.ofDays(performanceConfig.getRetentionDays()));
            
        } catch (Exception e) {
            log.error("记录慢操作失败", e);
        }
    }

    /**
     * 对SQL进行哈希处理
     */
    private String hashSql(String sql) {
        // 简化实现，实际应该使用更复杂的哈希算法
        return String.valueOf(sql.hashCode());
    }
}
